package cn.org.xiaosheng.server.handler;

import cn.org.xiaosheng.core.factory.ServiceFactory;
import cn.org.xiaosheng.core.message.RpcRequestMessage;
import cn.org.xiaosheng.core.message.RpcResponseMessage;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.ReferenceCountUtil;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * RPC请求处理器
 * @author XiaoSheng
 * @date 2024/8/21 上午11:26
 */
@Slf4j
@ChannelHandler.Sharable
public class RpcRequestMessageHandler extends SimpleChannelInboundHandler<RpcRequestMessage> {

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, RpcRequestMessage msg) throws Exception {
        RpcResponseMessage responseMessage = new RpcResponseMessage();
        // 设置请求的序号
        responseMessage.setSequenceId(msg.getSequenceId());
        Object result;

        try {
            //通过名称从工厂获取本地注解了@RpcServer的实例, 通过服务类名称获取对应的类实例
            Object service = ServiceFactory.serviceFactory.get(msg.getServiceName());
            // 获取方法，参数，
            Method method = service.getClass().getMethod(msg.getMethodName(), msg.getParameterTypes());
            // 调用
            result = method.invoke(service, msg.getParameterValue());
            System.out.println("result: " + result);
            // 此处对该对象进行toString编码,防止序列化等原因导致复杂对象消息无法传递至客户端
            responseMessage.setReturnValue(result.toString());
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            responseMessage.setExceptionValue(new Exception("远程调用出错: "+ e.getMessage()));
        } finally {
            ctx.writeAndFlush(responseMessage);
            /**
             * ReferenceCountUtil.release 方法是用来减少引用计数的。
             * 当一个引用计数对象不再被需要时，你应该调用这个方法来减少它的引用计数。
             * 如果引用计数减为零，Netty 将会自动释放该对象的内存。
             */
            ReferenceCountUtil.release(msg);
        }

    }

    /**
     * 读空闲
     * @param ctx
     * @param evt
     * @throws Exception
     */
    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent) {
            IdleState state = ((IdleStateEvent) evt).state();
            if (state == IdleState.READER_IDLE) {
                log.info("长时间未收到心跳包，断开连接...");
                ctx.close();
            }
        } else {
            super.userEventTriggered(ctx, evt);
        }
    }
}
